/**   
 * Copyright © 2016 深圳市欧唯科技有限公司. All rights reserved.
 * 
 * @Title: MyRealm.java 
 * @Prject: Web
 * @Package: com.adv.shiro 
 * @Description: TODO
 * @author: WUQINGLONG   
 * @date: 2016年9月5日 下午5:14:37 
 * @version: V1.0   
 */
package com.adv.shiro;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import com.adv.mapper.UserMapper;
import com.adv.model.PPermission;
import com.adv.model.PRole;
import com.adv.model.User;
import com.adv.model.UserSqlParam;

/**
 * @ClassName: MyRealm
 * @Description: 自定义认证权限领域类
 * @author: WUQINGLONG
 * @date: 2016年9月5日 下午5:14:37
 */
public class CustomRealm extends AuthorizingRealm {
	private static final String OR_OPERATOR = " or ";
	private static final String AND_OPERATOR = " and ";
	private static final String NOT_OPERATOR = "not ";
	private static final String ADMIN_ROLE_NAME = "superadmin";

	@Autowired
	private UserMapper userMapper;

	// 认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
			throws AuthenticationException {
		// UsernamePasswordToken对象用来存放提交的登录信息
		UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
		// 查出是否有此用户
		UserSqlParam param = new UserSqlParam();
		param.createCriteria().andUsernameEqualTo(token.getUsername());
		List<User> users = userMapper.selectByParam(param);
		if (!CollectionUtils.isEmpty(users)) {
			User user = users.get(0);
			// 若存在，将此用户存放到登录认证info中
			Session session = SecurityUtils.getSubject().getSession(true);
			session.setAttribute("uid", user.getId());
			if (!CollectionUtils.isEmpty(user.getRoles())) {
				String roleName = user.getRoles().get(0).getRoledesc();
				session.setAttribute("user_role_name", roleName);
			}
			return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
		}
		throw new UnknownAccountException();
	}

	// 授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		// 获取登录时输入的用户名
		String loginName = (String) principalCollection.fromRealm(getName()).iterator().next();
		// 到数据库查是否有此对象
		UserSqlParam param = new UserSqlParam();
		param.createCriteria().andUsernameEqualTo(loginName);
		List<User> users = userMapper.selectByParam(param);
		if (null != users && !users.isEmpty()) {
			User user = users.get(0);
			// 权限信息对象info,用来存放查出的用户的所有的角色（role）及权限（permission）
			SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
			List<PRole> roles = user.getRoles();
			Set<String> roleNames = new HashSet<String>();
			if (!CollectionUtils.isEmpty(roles)) {
				Set<String> permissionCodes = new HashSet<String>();
				for (PRole role : roles) {
					roleNames.add(role.getRolename());
					if (!CollectionUtils.isEmpty(role.getPermissions())) {
						permissionCodes.clear();
						for (PPermission permission : role.getPermissions()) {
							permissionCodes.add(permission.getCode());
						}
						simpleAuthorizationInfo.addStringPermissions(permissionCodes);
					}
				}
			}
			// 用户的角色集合
			simpleAuthorizationInfo.setRoles(roleNames);
			return simpleAuthorizationInfo;
		}
		throw new UnknownAccountException();
	}

	// 支持not and or的权限判断(and,or不能同用)
	// 例如：<shiro:hasPermission name="not show:tree:create or show:tree:update"
	// />
	@Override
	public boolean isPermitted(PrincipalCollection principals, String permission) {
		AuthorizationInfo authorizationInfo = getAuthorizationInfo(principals);
		if (isAdmin(authorizationInfo)) {
			return true;
		}
		if (permission.contains(OR_OPERATOR)) {
			String[] permissions = permission.split(OR_OPERATOR);
			for (String orPermission : permissions) {
				if (isPermittedWithNotOperator(principals, orPermission)) {
					return true;
				}
			}
			return false;
		} else if (permission.contains(AND_OPERATOR)) {
			String[] permissions = permission.split(AND_OPERATOR);
			for (String orPermission : permissions) {
				if (!isPermittedWithNotOperator(principals, orPermission)) {
					return false;
				}
			}
			return true;
		} else {
			return isPermittedWithNotOperator(principals, permission);
		}
	}

	private boolean isPermittedWithNotOperator(PrincipalCollection principals, String permission) {
		if (permission.startsWith(NOT_OPERATOR)) {
			return !super.isPermitted(principals, permission.substring(NOT_OPERATOR.length()));
		} else {
			return super.isPermitted(principals, permission);
		}
	}

	@Override
	protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {
		return isAdmin(info) || super.hasRole(roleIdentifier, info);
	}

	// admin 有所有权限
	private boolean isAdmin(AuthorizationInfo info) {
		if (info != null && info.getRoles() != null) {
			if (info.getRoles().contains(ADMIN_ROLE_NAME)) {
				return true;
			}
		}
		return false;
	}

}
